/**
 *
 */
package steven.location.activity;

import java.io.InputStream;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;

import steven.common.android.AndroidUtils;
import steven.fusion.R;
import steven.location.LocationPlugin;
import steven.location.service.LocationService;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.location.Location;
import android.location.LocationManager;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.Display;
import android.view.View;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

import com.google.android.gms.location.LocationListener;

/**
 * @author Steven
 *
 */
public class LocationActivity extends Activity implements LocationListener{
	private LocationPlugin plugin;
	private static int appWidth = 0;
	private static int appHeight = 0;
	private static int[] colors = null;
	private static byte[] buffer = null;
	private static long lastDirectionTime = 0;
	private static double lastNorthDirection = 0;
	private static double keepMoveDirection = Double.NaN;

	@Override
	protected void onCreate(final Bundle savedInstanceState){
		super.onCreate(savedInstanceState);
		super.setContentView(R.layout.location_activity);
		this.plugin = new LocationPlugin(this, this);
		super.findViewById(R.id.inputGroup).setVisibility(View.GONE);
		// get dimension
		if(LocationActivity.colors == null){
			final DisplayMetrics dm = new DisplayMetrics();
			final Display display = ((WindowManager)this.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
			display.getMetrics(dm);
			LocationActivity.appWidth = dm.widthPixels;
			LocationActivity.appHeight = 450;
			LocationActivity.colors = new int[LocationActivity.appWidth * LocationActivity.appHeight];
			LocationActivity.buffer = new byte[65536];
		}
	}
	@Override
	protected void onStart(){
		super.onStart();
		this.plugin.start();
	}
	@Override
	protected void onStop(){
		super.onStop();
		this.plugin.stop();
	}
	@Override
	protected void onResume(){
		super.onResume();
		if(AndroidUtils.isServiceRunning(this, LocationService.class)){
			((Button)super.findViewById(R.id.toggleServiceButton)).setText(R.string.stop_service);
		}else{
			((Button)super.findViewById(R.id.toggleServiceButton)).setText(R.string.start_service);
		}
		super.findViewById(R.id.toggleServiceButton).requestFocus();
	}
	@Override
	public void onLocationChanged(final Location location){
		((TextView)super.findViewById(R.id.gmsLabel)).setText(new SimpleDateFormat("HH:mm:ss", Locale.US).format(new Date()) + " " + location.getProvider() + " " + location.getAccuracy() + " " + location.getLatitude() + "," + location.getLongitude());
	}
	public void toggleService(final View view){
		final Intent service = new Intent(view.getContext(), LocationService.class);
		if(AndroidUtils.isServiceRunning(this, LocationService.class)){
			super.stopService(service);
			((Button)super.findViewById(R.id.toggleServiceButton)).setText(R.string.start_service);
			Toast.makeText(this, "Stopping service...", Toast.LENGTH_SHORT).show();
		}else{
			super.startService(service);
			((Button)super.findViewById(R.id.toggleServiceButton)).setText(R.string.stop_service);
			Toast.makeText(this, "Starting service...", Toast.LENGTH_SHORT).show();
		}
	}
	public void setMockLocation(final View view){
		final View inputGroup = super.findViewById(R.id.inputGroup);
		if(inputGroup.getVisibility() == View.GONE){
			inputGroup.setVisibility(View.VISIBLE);
		}else{
			this.setMockLocation(Double.parseDouble(((EditText)super.findViewById(R.id.latitudeText)).getText().toString()), Double.parseDouble(((EditText)super.findViewById(R.id.longitudeText)).getText().toString()));
			inputGroup.setVisibility(View.GONE);
		}
	}
	public void goHome(final View view){
		this.setMockLocation(22.341768, 114.207806);
	}
	public void goOffice(final View view){
		this.setMockLocation(22.33828, 114.145797);
	}
	private void setMockLocation(final double latitude, final double longitude){
		final LocationManager locationManager = (LocationManager)super.getSystemService(Context.LOCATION_SERVICE);
		LocationActivity.setMockLocation(locationManager, latitude, longitude);
	}
	public static final void setMockLocation(final LocationManager locationManager, final double latitude, final double longitude){
		final Location location = new Location(LocationManager.GPS_PROVIDER);
		location.setLatitude(latitude);
		location.setLongitude(longitude);
		location.setTime(System.currentTimeMillis());
		locationManager.setMockLocation(location);
	}
	public static final void move(final Context context, final double directionOffset, final double distance){
		final LocationManager locationManager = (LocationManager)context.getSystemService(Context.LOCATION_SERVICE);
		final Location location = locationManager.getMockLocation();
		final double direction = directionOffset - LocationActivity.getIngressDirection(context);
		LocationActivity.setMockLocation(locationManager, location.getLatitude() + distance * Math.cos(direction), location.getLongitude() + distance * Math.sin(direction));
		if(Double.isNaN(LocationActivity.keepMoveDirection)){
			LocationActivity.keepMoveDirection = direction;
		}
	}
	public static final double getIngressDirection(final Context context){
		synchronized(LocationActivity.colors){
			double northDirection = LocationActivity.lastNorthDirection;
			final long now = System.currentTimeMillis();
			if(now - LocationActivity.lastDirectionTime > 5000){
				try{
					// use screencap
					final Process p = Runtime.getRuntime().exec("su");
					final OutputStream os = p.getOutputStream();
					os.write("/system/bin/screencap".getBytes());
					os.flush();
					os.close();
					// read buffer
					final InputStream is = p.getInputStream();
					int size = 0;
					int offset = 0;
					int index = 0;
					while((size = is.read(LocationActivity.buffer, offset, LocationActivity.buffer.length - offset)) >= 0 && index < LocationActivity.colors.length){
						final int count = ((offset + size) >> 2);
						for(int i = 0, j = 0; i < count && index < LocationActivity.colors.length; i++){
							final int r = LocationActivity.buffer[j++];
							final int g = LocationActivity.buffer[j++];
							final int b = LocationActivity.buffer[j++];
							final int a = LocationActivity.buffer[j++];
							LocationActivity.colors[index++] = (a << 24) + (r << 16) + (g << 8) + b;
						}
						final int endIndex = (count << 2);
						offset = (offset + size) & 0x3;
						if(offset == 1){
							LocationActivity.buffer[0] = LocationActivity.buffer[endIndex];
						}else if(offset == 2){
							LocationActivity.buffer[0] = LocationActivity.buffer[endIndex];
							LocationActivity.buffer[1] = LocationActivity.buffer[endIndex + 1];
						}else if(offset == 3){
							LocationActivity.buffer[0] = LocationActivity.buffer[endIndex];
							LocationActivity.buffer[1] = LocationActivity.buffer[endIndex + 1];
							LocationActivity.buffer[2] = LocationActivity.buffer[endIndex + 2];
						}
					}
					is.close();
					p.waitFor();
					final int centerX = 100;
					final int centerY = 345;
					final int radius = 80;
					int northX = centerX;
					int northY = centerY;
					double northDistance = 0;
					for(int y = centerY - radius; y <= centerY + radius; y++){
						for(int x = centerX - radius; x <= centerX + radius; x++){
							final int color = LocationActivity.colors[y * LocationActivity.appWidth + x];
							final int red = (color >> 16) & 0xff;
							final int green = (color >> 8) & 0xff;
							final int blue = (color) & 0xff;
							if(red >= 180 && green <= 48 && blue <= 48){
								final double distance = Math.sqrt((x - centerX) * (x - centerX) + (y - centerY) * (y - centerY));
								if(distance > northDistance){
									northX = x;
									northY = y;
									northDistance = distance;
								}
							}
						}
					}
					if(northDistance > 10){
						northDirection = Math.atan2(northY - centerY, northX - centerX) + Math.PI / 2;
						int angle = (int)(northDirection / Math.PI * 180);
						if(angle < 0){
							angle += 360;
						}
						LocationActivity.lastDirectionTime = now;
						Log.e("steven", "angle: " + angle);
					}else{
						Toast.makeText(context, "Cannot find north.", Toast.LENGTH_SHORT).show();
					}
				}catch(final Exception e){
					Log.e("steven", "cap screen error", e);
				}
			}
			LocationActivity.lastNorthDirection = northDirection;
			return northDirection;
		}
	}
	public static final void resetKeepMoving(){
		LocationActivity.keepMoveDirection = Double.NaN;
	}
	public static final boolean keepMoving(final Context context, final double distance){
		if(Double.isNaN(LocationActivity.keepMoveDirection)){
			return false;
		}else{
			final LocationManager locationManager = (LocationManager)context.getSystemService(Context.LOCATION_SERVICE);
			final Location location = locationManager.getMockLocation();
			LocationActivity.setMockLocation(locationManager, location.getLatitude() + distance * Math.cos(LocationActivity.keepMoveDirection), location.getLongitude() + distance * Math.sin(LocationActivity.keepMoveDirection));
			return true;
		}
	}
}
